package com.bwie.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bwie.domain.TbCheck;
import com.bwie.domain.TbUser;
import com.bwie.es.EsUser;
import com.bwie.mapper.TbCheckMapper;
import com.bwie.mapper.TbUserMapper;
import com.bwie.service.TbUserService;
import com.bwie.state.UserRoleEnum;
import com.bwie.utils.MobileMessageUtil;
import com.bwie.utils.R;
import com.bwie.vo.CheckUserVo;
import com.bwie.vo.LoginInfoVo;
import com.bwie.vo.PageInfoVo;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author 军哥
 * @version 1.0
 * @description: TODO
 * @date 2024/10/15 16:08
 */

@Service
public class TbUserServiceImpl implements TbUserService {

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Autowired
    TbUserMapper tbUserMapper;

    @Autowired
    TbCheckMapper tbCheckMapper;

    @Autowired
    ElasticsearchRestTemplate elasticsearchRestTemplate;

    @Autowired
    HttpServletRequest request;

    @Override
    public R sendCode(String mobile) {
        // 后端校验手机号（糊涂工具类）
        boolean m = Validator.isMobile(mobile);
        if(!m) {
            return R.ERROR(500, "手机号格式不正确");
        }

//        boolean email = Validator.isEmail(mobile);
//        if(!email) {
//            return R.ERROR(500, "邮箱格式不正确");
//        }
//
//        boolean chinese = Validator.isChinese("中国");
//        if(!chinese) {
//            return R.ERROR(500, "非中文，请输入中文");
//        }



        //-- 生成验证码
        String code = RandomUtil.randomNumbers(6);
        System.out.println("验证码：" + code);

        //-- 发送验证码
        Boolean ok = MobileMessageUtil.sendMobileMessage(mobile, code);
        if(!ok) {
            System.out.println("短信验证码发送失败，再次发送");
            MobileMessageUtil.sendMobileMessage(mobile, code);
        }

        //-- 把验证码放到缓存中（过期时间5分钟）
        String key = "code-" + mobile;
        stringRedisTemplate.opsForValue().set(key, code, 5, TimeUnit.MINUTES);

        return R.OK(code);
    }

    @Override
    public R login(LoginInfoVo loginInfoVo) {
        //-- 校验验证码
        String key = "code-" + loginInfoVo.getUserMobile();
        String code = stringRedisTemplate.opsForValue().get(key);
        if(code == null) {
            return R.ERROR(500, "验证码已过期，请重新获取");
        }
        if(!code.equals(loginInfoVo.getUserCode())) {
            return R.ERROR(500, "验证码错误，请重新输入");
        }

        //-- 读取用户信息
        TbUser tbUser = tbUserMapper.selectOne(
                new QueryWrapper<TbUser>().lambda().eq(TbUser::getUserMobile, loginInfoVo.getUserMobile())
        );
        if(tbUser == null) {
            return R.ERROR(500, "用户不存在，请先注册");
        }

        //-- 生成token
        String token = Jwts.builder()
                .signWith(SignatureAlgorithm.HS256, "123456")
                .claim("userId", tbUser.getUserId())
                .claim("userName", tbUser.getUserName())
                .compact();
        String tokenKey = "token-" +tbUser.getUserId();
        stringRedisTemplate.opsForValue().set(tokenKey, token, 30, TimeUnit.MINUTES);

        //-- 返回用户信息
        tbUser.setToken(token);

        return R.OK(tbUser);
    }

    @Override
    public R getUserById(Integer userId) {
        TbUser tbUser = tbUserMapper.selectById(userId);
        return R.OK(tbUser);
    }

    @Override
    public R loginByName(LoginInfoVo loginInfoVo) {
        //-- 读取用户信息
        TbUser tbUser = tbUserMapper.selectOne(
                new QueryWrapper<TbUser>().lambda().eq(TbUser::getUserName, loginInfoVo.getUserName())
        );
        if(tbUser == null) {
            return R.ERROR(500, "用户不存在，请先注册");
        }

        //-- 校验密码
        if(!loginInfoVo.getUserPass().equals(tbUser.getUserPass())) {
            return R.ERROR(500, "密码错误，请重新输入");
        }

        //-- 生成token
        String token = Jwts.builder()
                .signWith(SignatureAlgorithm.HS256, "123456")
                .claim("userId", tbUser.getUserId())
                .claim("userName", tbUser.getUserName())
                .compact();
        String tokenKey = "token-" + tbUser.getUserId();
        stringRedisTemplate.opsForValue().set(tokenKey, token, 30, TimeUnit.MINUTES);

        //-- 返回用户信息
        tbUser.setToken(token);

        return R.OK(tbUser);
    }

    @Override
    public R shoperRegister(TbUser tbUser) {
        //-- 校验用户名
        TbUser one = tbUserMapper.selectOne(
                new QueryWrapper<TbUser>().lambda().eq(TbUser::getUserName, tbUser.getUserName())
        );
        if(one != null) {
            return R.ERROR(500, "用户名已存在");
        }

        //-- 添加商户
        tbUser.setCreateTime(new Date());
        tbUser.setUserRole(UserRoleEnum.SHOP.getCode());
        tbUserMapper.insert(tbUser);
        return R.OK();
    }

    @Override
    public R getUserList(PageInfoVo pageInfoVo) {
        // 构造分页参数
        Page<TbUser> page = new Page<>(pageInfoVo.getPageNum(), pageInfoVo.getPageSize());

//        // 构造查询条件
//        QueryWrapper<TbUser> wrapper = new QueryWrapper<>();
//        // 根据用户角色进行查询
//        if(pageInfoVo.getTypeId() != null) {
//            wrapper.lambda().eq(TbUser::getUserRole, pageInfoVo.getTypeId());
//        }
//        // 根据关键字进行查询
//        if(!StringUtils.isEmpty(pageInfoVo.getKeyWord())) {
//            wrapper.lambda()
//                    .like(TbUser::getUserName, pageInfoVo.getKeyWord())
//                    .or()
//                    .like(TbUser::getNickName, pageInfoVo.getKeyWord())
//                    .or()
//                    .like(TbUser::getUserMobile, pageInfoVo.getKeyWord());
//        }
//        wrapper.lambda().orderByDesc(TbUser::getUserId);


//        IPage<TbUser> tbUserIPage = tbUserMapper.selectPage(page, wrapper);
        TbUser tbUser = new TbUser();
        tbUser.setUserRole(pageInfoVo.getTypeId());
        IPage<TbUser> userByPage = tbUserMapper.getUserByPage(page, tbUser);

        return R.OK(userByPage);
    }

    @Override
    public List<TbUser> getAllUserList(int roleId) {
        List<TbUser> tbUsers = tbUserMapper.selectList(
                new QueryWrapper<TbUser>().lambda().eq(TbUser::getUserRole, roleId)
        );
        return tbUsers;
    }

    @Override
    public R getUserListFromEs(PageInfoVo pageInfoVo) {
        //--1 构造分页参数
        Integer pageNum = 0;
        if(pageInfoVo.getPageNum() > 0) {
            pageNum = pageInfoVo.getPageNum() - 1;
        }
        PageRequest pageRequest = PageRequest.of(pageNum, pageInfoVo.getPageSize());

        //--2 构造查询条件

        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        if(!StringUtils.isEmpty(pageInfoVo.getKeyWord())) {
            // 昵称查询
            boolQueryBuilder.should(QueryBuilders.matchQuery("nickName", pageInfoVo.getKeyWord()));
            // 账号查询
            boolQueryBuilder.should(QueryBuilders.matchQuery("userName", pageInfoVo.getKeyWord()));
            // 手机号查询
            boolQueryBuilder.should(QueryBuilders.matchQuery("userMobile", pageInfoVo.getKeyWord()));
        }

        // 增加高亮
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("nickName").preTags("<font color='red'>").postTags("</font>");

        // 时间区间查询
        if(!StringUtils.isEmpty(pageInfoVo.getBeginTime()) && !StringUtils.isEmpty(pageInfoVo.getEndTime())) {
            boolQueryBuilder.must(
                    QueryBuilders.rangeQuery("createTime")
                            .format("yyyy-MM-dd HH:mm:ss")
                            .timeZone("GMT+8")
                            .gte(pageInfoVo.getBeginTime())
                            .lte(pageInfoVo.getEndTime())
            );
        }

        // 排序（根据用户ID倒叙排列）
        FieldSortBuilder sortBuilder = new FieldSortBuilder("userId").order(SortOrder.DESC);

        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        nativeSearchQueryBuilder.withPageable(pageRequest)
                .withQuery(boolQueryBuilder)
                .withHighlightBuilder(highlightBuilder)
                .withSort(sortBuilder);

        //--3 开始查询
        SearchHits<EsUser> searchHits = elasticsearchRestTemplate.search(nativeSearchQueryBuilder.build(), EsUser.class);

        //--4 读取查询结果
        long total = searchHits.getTotalHits();

        ArrayList<EsUser> records = new ArrayList<>();
        for (SearchHit<EsUser> searchHit : searchHits.getSearchHits()) {
            EsUser esUser = searchHit.getContent();

            // 读取高亮信息
            List<String> list = searchHit.getHighlightField("nickName");
            if(list != null && list.size()>0) {
                esUser.setNickName(list.get(0));
            }

            records.add(esUser);
        }

        //--5 构造返回结果
        HashMap<String, Object> map = new HashMap<>();

        map.put("total", total);
        map.put("records", records);
        return R.OK(map);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public R checkUser(CheckUserVo checkUserVo) {
        //-- 判断商家是否存在
        TbUser tbUser = tbUserMapper.selectById(checkUserVo.getUserId());
        if(tbUser == null) {
            return R.ERROR(500, "用户不存在");
        }

        //-- 更新审核状态
        tbUser.setUserCheck(checkUserVo.getCheckFlag());
        tbUserMapper.updateById(tbUser);

        //-- 记录审核的结果
        // 通过token解析操作者信息
        String token = request.getHeader("token");
        Claims body = Jwts.parser().setSigningKey("123456").parseClaimsJws(token).getBody();
        Integer userId = body.get("userId", Integer.class);
        TbUser optUser = tbUserMapper.selectById(userId);

        // 实时同步数据到ES中
        EsUser esUser = BeanUtil.toBean(tbUser, EsUser.class);
        elasticsearchRestTemplate.save(esUser);

        // 生成审核记录
        TbCheck tbCheck = new TbCheck();
        tbCheck.setUserId(tbUser.getUserId());
        tbCheck.setNickName(tbUser.getNickName());
        tbCheck.setUserCheck(checkUserVo.getCheckFlag());
        tbCheck.setCheckUser(optUser.getUserId());
        tbCheck.setCheckName(optUser.getNickName());
        tbCheck.setCreateTime(new Date());
        tbCheck.setCheckReason(checkUserVo.getCheckReason());
        tbCheckMapper.insert(tbCheck);

        // 发送Kafka消息，通知用户审核的进展

        return R.OK();
    }

    @Override
    public R subUserMoney(Integer userId, Double userMoney) {
        //--1 获取当前用户信息
        TbUser tbUser = tbUserMapper.selectById(userId);
        if(tbUser == null) {
            return R.ERROR(500, "用户不存在");
        }

        // 检查余额
        if(tbUser.getUserMoney() < userMoney) {
            return R.ERROR(500, "余额不足");
        }

        //--2 扣减余额
        tbUser.setUserMoney(tbUser.getUserMoney() - userMoney);
        tbUserMapper.updateById(tbUser);

        return R.OK();
    }
}
